﻿Imports System.ComponentModel.Composition.Hosting
Imports System.ComponentModel.Composition

Public Class InfoProccessors
    Implements IDisposable

    Private _container As CompositionContainer

    <ImportMany()>
    Protected Property InfoProccessor As IEnumerable(Of Lazy(Of IInfoProccessor, IExtensionCompentMetadata))

    Private _EnableProccessors As Dictionary(Of String, Tuple(Of Boolean, Integer))
    Public Property EnableProccessors As Dictionary(Of String, Tuple(Of Boolean, Integer))
        Get
            If _EnableProccessors Is Nothing Then _EnableProccessors = New Dictionary(Of String, Tuple(Of Boolean, Integer))
            Return _EnableProccessors
        End Get
        Set(ByVal value As Dictionary(Of String, Tuple(Of Boolean, Integer)))
            _EnableProccessors = value
        End Set
    End Property

    Public Function GetAvailabilities() As Dictionary(Of String, Boolean)
        Dim d As Dictionary(Of String, Boolean)
        Try
            Dim query = From proc In InfoProccessor Select k = proc.Metadata.Name, v = proc.Value.GetAvailability

            d = query.ToDictionary(Function(k) k.k, Function(v) v.v)
        Catch ex As Exception
            d = New Dictionary(Of String, Boolean)
        End Try
        Return d
    End Function
    Protected _ProccessorNames As IEnumerable(Of String)
    Public ReadOnly Property ProccessorNames As IEnumerable(Of String)
        Get
            Return _ProccessorNames
        End Get
    End Property

    Public Function ProccessInfo(ByVal infos As Dictionary(Of String, String)) As String
        Dim q = From proc In InfoProccessor.AsParallel.AsOrdered
                Where proc.Value.GetAvailability = True AndAlso EnableProccessors.ContainsKey(proc.Metadata.Name) AndAlso EnableProccessors(proc.Metadata.Name).Item1 = True
              Order By EnableProccessors(proc.Metadata.Name).Item2 Ascending Select proc.Value

        On Error Resume Next
        For Each p In q.AsEnumerable
            Return p.ProccessInfo(infos)
        Next
        On Error GoTo 0
        Return String.Empty
    End Function

    Public Sub ShowSetting(procName As String)
        Dim proc = InfoProccessor.Where(Function(p) p.Metadata.Name = procName).FirstOrDefault
        If proc IsNot Nothing Then
            proc.Value.ShowSetting()
        End If
    End Sub

    Private Sub Init(ByVal paths As IEnumerable(Of String))
        Dim catalog = New AggregateCatalog()
        catalog.Catalogs.Add(New AssemblyCatalog(GetType(InfoProccessors).Assembly))
        For Each path In paths
            If Not String.IsNullOrEmpty(path) Then
                If IO.Directory.Exists(path) Then
                    catalog.Catalogs.Add(New DirectoryCatalog(path))
                End If
            End If
        Next
        _container = New CompositionContainer(catalog)
        Try
            _container.ComposeParts(Me)
            If InfoProccessor IsNot Nothing Then
                Dim names As New List(Of String)
                For Each IProc In InfoProccessor
                    IProc.Value.StartUp()
                    names.Add(IProc.Metadata.Name)
                    If EnableProccessors.ContainsKey(IProc.Metadata.Name) Then
                        EnableProccessors.Add(IProc.Metadata.Name, Tuple.Create(Of Boolean, Integer)(False, Integer.MaxValue))
                    End If
                Next
                _ProccessorNames = names
            End If
        Catch ex As Exception
            Debug.WriteLine(ex.ToString)
            Throw
        End Try
    End Sub

    Public Sub New()
        Me.New({IO.Path.GetFullPath(".")})
    End Sub

    Public Sub New(ByVal paths As IEnumerable(Of String))
        Init(paths)
    End Sub
#Region "IDisposable Support"
    Private disposedValue As Boolean ' 检测冗余的调用

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: 释放托管状态(托管对象)。
                If InfoProccessor IsNot Nothing Then
                    Try
                        Dim q = From p In InfoProccessor.AsParallel

                        q.ForAll(Sub(p) p.Value.ShutDown())
                    Catch

                    Finally
                        InfoProccessor = Nothing
                    End Try
                End If
                If _container IsNot Nothing Then
                    _container.Dispose()
                    _container = Nothing
                End If
                _EnableProccessors = Nothing
            End If

            ' TODO: 释放非托管资源(非托管对象)并重写下面的 Finalize()。
            ' TODO: 将大型字段设置为 null。
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: 仅当上面的 Dispose(ByVal disposing As Boolean)具有释放非托管资源的代码时重写 Finalize()。
    'Protected Overrides Sub Finalize()
    '    ' 不要更改此代码。请将清理代码放入上面的 Dispose(ByVal disposing As Boolean)中。
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' Visual Basic 添加此代码是为了正确实现可处置模式。
    Public Sub Dispose() Implements IDisposable.Dispose
        ' 不要更改此代码。请将清理代码放入上面的 Dispose(ByVal disposing As Boolean)中。
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class
